
FUNCTION flipof(*oldcolor: color): color*);
BEGIN
IF oldcolor = white THEN
   flipof := black
ELSE
   flipof := white;
END; (*flipof*)

PROCEDURE updatecrt(*VAR oldstatus,newstatus: gamestatus*);
VAR
   x,y:         coordinate;
   direc:       direction;
   square:      squareloc;

   PROCEDURE showpiece(square: squareloc);
      
      PROCEDURE changecrtsq(square: squareloc);
      CONST
         bell = 7;
      VAR
         s:                     PACKED ARRAY[1..3] OF CHAR;
         c:                     CHAR;
         crtline,crtcol:        INTEGER;
         h,l:                   INTEGER;
         now:                   REAL;
      BEGIN
      WITH square DO BEGIN
         IF newstatus.boardstatus[row,col].occupier = white THEN
            c := CHR(whiteascii)
         ELSE
            c := CHR(blackascii);
         FILLCHAR(s,3,c);
         crtline := (3*row) - 3;
         crtcol  := 26 + (6*col);
         END;
      REPEAT
         TIME(h,l);
         now := l;
         IF now < 0.0 THEN
            now := now + 65536.0;
         now := (h*65536.0) + now;
         UNTIL (now - lastchange) > minticks; 
      GOTOXY(crtcol,crtline);
      WRITE(s);
      GOTOXY(crtcol,crtline+1);
      WRITE(s,CHR(bell));
      lastchange := now;
      END; (*changecrtsq*)
   
   BEGIN (*showpiece*)
   WITH square DO
      IF newstatus.boardstatus[row,col].occupied THEN
         IF NOT oldstatus.boardstatus[row,col].occupied THEN
            changecrtsq(square)
         ELSE IF oldstatus.boardstatus[row,col].occupier <>
                 newstatus.boardstatus[row,col].occupier THEN
                 changecrtsq(square);
   END; (*showpiece*)

BEGIN (*updatecrt*)
WITH newstatus DO BEGIN
   showpiece(lastmoveloc);
   FOR direc := north to nw DO BEGIN
      square := lastmoveloc;
      WHILE boardstatus[square.row,square.col].occupied AND
            board[square.row,square.col].adjacentsq[direc].onboard DO BEGIN
         square := board[square.row,square.col].adjacentsq[direc];
         showpiece(square);
         END; (*WHILE...*)
      END; (*FOR direc...*)
   GOTOXY(9,2);
   WRITE(score[white]:2);
   GOTOXY(9,3);
   write(score[black]:2);
   END; (*WITH newstatus...*)
GOTOXY(0,0);
END; (*updatecrt*)

PROCEDURE findlegalmoves(VAR status: gamestatus; VAR legallist: movelist);
VAR
   x,y:                   coordinate;
   sq:                    squareloc;
   flips,direcflips:      INTEGER;
   borderflips:           INTEGER;
   stopdirec:             BOOLEAN;
   oppcolor:              color;
   direc:                 direction;
   trydirs,gooddirs:      SET OF direction;
   possible:              BOOLEAN;
   sqstatus:              squarestatus;
BEGIN
WITH status, legallist DO BEGIN
   oppcolor := flipof(nextmover);
   movecount := 0;
   FOR x := 1 TO 8 DO  FOR y := 1 TO 8 DO BEGIN
      possible := FALSE;
      WITH boardstatus[x,y] DO
         IF NOT occupied THEN
            IF adjacentpieces[oppcolor] <> [] THEN BEGIN
               possible := TRUE;
               trydirs := adjacentpieces[oppcolor];
               END;
      IF possible THEN BEGIN
         gooddirs := [];
         flips := 0;
         borderflips := 0;
         FOR direc := north TO nw DO
            IF direc IN trydirs THEN BEGIN
               sq := board[x,y].adjacentsq[direc];
               sq := board[sq.row,sq.col].adjacentsq[direc];
               IF sq.onboard THEN BEGIN
                  direcflips := 1;
                  stopdirec := FALSE;
                  REPEAT
                     sqstatus := boardstatus[sq.row,sq.col];
                     IF sqstatus.occupied THEN
                        IF sqstatus.occupier = oppcolor THEN BEGIN
                           direcflips := direcflips + 1;
                           sq := board[sq.row,sq.col].adjacentsq[direc];
                           END
                        ELSE
                           stopdirec := TRUE
                     ELSE BEGIN
                        direcflips := 0;
                        stopdirec := TRUE;
                        END;
                     UNTIL ( stopdirec OR (NOT sq.onboard) );
                  IF (stopdirec AND (direcflips>0)) THEN BEGIN
                     flips := flips + direcflips;
                     gooddirs := gooddirs + [direc];
                     IF board[x,y].border AND board[sq.row,sq.col].border THEN
                        borderflips := borderflips + direcflips;
                     END;
                  END; (*IF sq.onboard...*)
               END; (*IF direc IN...*)
         IF flips > 0 THEN BEGIN
            movecount := movecount + 1;
            WITH okmove[movecount] DO BEGIN
               moveloc.onboard := TRUE;
               moveloc.row := x;
               moveloc.col := y;
               points := flips;
               dirsflipped := gooddirs;
               bordrsqsflipped := borderflips;
               END;
            END;
         END; (*IF possible...*)
      END; (*FOR x :=...FOR y :=...*)
   END; (*WITH status, legallist...*)
END; (*findlegalmoves*)

PROCEDURE inputmove(mover: color; legallist: movelist; VAR move: movedesc);
VAR
   x,y:                 coordinate;
   xch,ych:             CHAR;
   i,listindex:         INTEGER;
   c:                   CHAR;
BEGIN
listindex := 0;
REPEAT
   REPEAT
      GOTOXY(0,23);
      WRITE('Enter move for ',colorword[mover],':        ');
      GOTOXY(22,23);
      READ(xch,ych);
      IF ych IN ['1'..'8'] THEN BEGIN (*Want xy but we'll accept yx*)
         c := ych;
         ych := xch;
         xch := c;
         END;
      IF ych IN ['a'..'h'] THEN
         ych := CHR(ORD(ych)-32);
      UNTIL ((xch IN ['1'..'8']) AND (ych IN ['A'..'H']));
   x := ORD(xch) - ORD('1') + 1;
   y := ORD(ych) - ORD('A') + 1;
   i := 1;
   REPEAT
      IF legallist.okmove[i].moveloc.row = x THEN
         IF legallist.okmove[i].moveloc.col = y THEN
            listindex := i;
      i := i+1;
      UNTIL ((i>legallist.movecount) OR (listindex <> 0));
   UNTIL listindex <> 0;
move := legallist.okmove[listindex];
END; (*inputmove*)

PROCEDURE makemove(*VAR status: gamestatus; VAR move: movedesc; updateadjacent:
                                                                BOOLEAN*);
VAR
   direc,direc2:       direction;
   sq,sq2:             squareloc;
   oppcolor:           color;
   flips:              INTEGER;
   emptyneighbors:     SET of direction;
BEGIN
WITH status, move DO BEGIN
   lastmoveloc := moveloc;
   WITH boardstatus[moveloc.row,moveloc.col] DO BEGIN
      emptyneighbors := [north..nw] - adjacentpieces[white]
                                    - adjacentpieces[black];
      occupied := TRUE;
      occupier := nextmover;
      END;
   oppcolor := flipof(nextmover);
   flips := 0;
   FOR direc := north TO nw DO
      IF direc IN dirsflipped THEN BEGIN
         sq := board[moveloc.row,moveloc.col].adjacentsq[direc];
         REPEAT
            IF updateadjacent THEN
               FOR direc2 := north TO nw DO
                  IF NOT (direc2 IN [direc,opposdir[direc]]) THEN BEGIN
                     sq2 := board[sq.row,sq.col].adjacentsq[direc2];
                     IF sq2.onboard THEN WITH boardstatus[sq2.row,sq2.col] DO
                        IF NOT occupied THEN BEGIN
                           adjacentpieces[nextmover]:=adjacentpieces[nextmover]
                                                        + [opposdir[direc2]];
                           adjacentpieces[oppcolor]:=adjacentpieces[oppcolor]
                                                        - [opposdir[direc2]];
                           END;
                     END;
            boardstatus[sq.row,sq.col].occupier := nextmover;
            flips := flips + 1;
            sq := board[sq.row,sq.col].adjacentsq[direc];
            UNTIL boardstatus[sq.row,sq.col].occupier = nextmover;
         END
      ELSE
         IF updateadjacent THEN
            IF direc IN emptyneighbors THEN BEGIN
               sq := board[moveloc.row,moveloc.col].adjacentsq[direc];
               IF sq.onboard THEN
                  WITH boardstatus[sq.row,sq.col] DO
                     adjacentpieces[nextmover] := adjacentpieces[nextmover] + 
                                                  [opposdir[direc]];
               END;
   score[nextmover] := score[nextmover] + flips + 1;
   score[oppcolor]  := score[oppcolor] - flips;
   nextmover := oppcolor;
   END;
END; (*makemove*)


